package com.sghd.football.module.data.service;

import com.sghd.common.socket.utils.NamedThreadFactory;
import com.sghd.common.utils.json.JsonUtils;
import com.sghd.football.module.data.dao.MysqlTemplate;
import com.sghd.football.module.data.entity.RecordPropModify;
import com.sghd.football.module.data.entity.RecordSettleError;
import com.sghd.football.module.game.service.core.Player;
import com.sghd.football.module.game.service.model.PropType;
import com.sghd.football.module.game.service.model.Result;
import com.sghd.football.module.game.service.model.ReturnMsg;
import com.sghd.football.module.game.service.model.Window;
import com.sghd.football.utils.ManagedException;
import com.sghd.football.utils.http.HttpConfig;
import com.sghd.football.utils.http.HttpUtil;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * \* Created with 王创辉.
 * \* Date: 2018/5/29
 * \* Time: 13:53
 * \* @desc:
 */
@Component
public class DataServiceImpl implements DataService {
    @Value("${data.pool.size:6}")
    private int coreSize;
    private static Logger logger = LoggerFactory.getLogger(DataService.class);
    /**
     * 耗时操作线程池
     */
    private ThreadPoolExecutor executor;
    @Autowired
    private MysqlTemplate mysqlTemplate;

    @PostConstruct
    void init() {
        executor = new ThreadPoolExecutor(coreSize, Integer.MAX_VALUE, 60,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("数据服务线程"));
        executor.allowCoreThreadTimeOut(true);
    }

    @Override
    public boolean settle(Player player, Result result) throws Exception {
        long change = result.getTotalFen() - result.getTotalBet();
        long current = player.getMondey(PropType.GOLD);//当前金币
        //数据服结算
        if (change != 0) {
            updatePlayerPropInfo(player.getPlayerId(), player.getGameId(), 1, PropType.GOLD.getValue() + ":" + change + ";", current);
        }
        RecordPropModify record = new RecordPropModify();
        if (result.isMgame()) {
            record.setRemark("得分(小游戏):" + result.getTotalFen() + "@" + JsonUtils.object2String(result.getSequence()));
        } else {
            record.setRemark("得分:" + result.getTotalFen() + "@押注:" + result.getTotalBet() + "@免费:" + result.isCurrentFree() + "@" + JsonUtils.object2String(result.getSequence()));
        }
        record.setPlayerId(player.getPlayerId());
        record.setNickName(player.getNickName());
        record.setGameId(player.getGameId());
        record.setRoomId(player.getRoomId());
        record.setDeskId(player.getDeskId());
        record.setSeatId(player.getSeat());
        record.setPropId(PropType.GOLD.getValue());
        record.setChangeNum(change);
        record.setChangeSource(1);
        record.setTaxNum(0l);
        record.setShowToPlayer("游戏结算：" + change);
        record.setCreateTime(new Date());
        mysqlTemplate.insert(record);
        return true;
    }

    /**
     * 保存结算失败的数据
     * */
    public void settleError(Player player, Result result, Throwable ex) {
        long change = result.getTotalFen() - result.getTotalBet();
        RecordSettleError error = new RecordSettleError();
        error.setChange(change);
        error.setPlayerId(player.getPlayerId());
        error.setName(player.getNickName());
        error.setResult(JsonUtils.object2String(result));
        error.setTotalBet(result.getTotalBet());
        error.setTotalFen(result.getTotalFen());
        if (result.isMgame()) {
            error.setRemark("得分(小游戏):" + result.getTotalFen() + "@" + JsonUtils.object2String(result.getSequence()));
        } else {
            error.setRemark("得分:" + result.getTotalFen() + "@押注:" + result.getTotalBet() + "@免费:" + result.isCurrentFree() + "@" + JsonUtils.object2String(result.getSequence()));
        }
        if (ex != null) {
            error.setException(ex.getMessage());
        }
        mysqlTemplate.insert(error);
    }


    @Override
    public void submit(Runnable runnable) {
        executor.submit(runnable);
    }

    /**
     * 游戏数据结算
     * @param changeSource 货币更忙来源(1:游戏结算)
     * @param detail --> 道具详情（propID:propNum;propID:propNum）
     **/
    public void updatePlayerPropInfo(Long playerId, int gameId, Integer changeSource, String detail,
                                     long beforeMoney) throws Exception {
        Map<String, Object> json = new HashMap<>();
        json.put("action", "update");
        json.put("beforeMoney", beforeMoney);
        json.put("playerID", playerId);
        json.put("gameID", gameId);
        json.put("detail", detail);
        json.put("changeSource", changeSource);
        ReturnMsg rmsg = HttpUtil.sendData(json, HttpConfig.send_post, HttpConfig.encrypt_java, "hallServlet");
        json.clear();
        if (rmsg.getState() != 1) {
            throw new RuntimeException(rmsg.getInfo());
        }
    }

    /**
     * 进入游戏房间
     **/
    public boolean intoRoom(long playerId, int gameId, int roomId) {
        Map<String, Object> params = new HashMap<>();
        params.put("action", "intoRoom");
        params.put("playerID", playerId);
        params.put("gameID", gameId);
        params.put("roomID", roomId);
        ReturnMsg rmsg = new ReturnMsg();
        try {
            rmsg = HttpUtil.sendData(params, HttpConfig.send_post, HttpConfig.encrypt_java, "hallServlet");
            logger.debug("玩家[{}]进入房间", playerId);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        params.clear();
        if (rmsg.getState() == 1) {
            return true;
        }
        return false;
    }


    /** 离开游戏房间 **/
    public void outRoom(long playerId, int gameId, int roomId) {
        submit(() -> {
            Map<String, Object> params = new HashMap<>();
            params.put("action", "leaveRoom");
            params.put("playerID", playerId);
            params.put("gameID", gameId);
            params.put("roomID", roomId);
            try {
                HttpUtil.sendData(params, HttpConfig.send_post, HttpConfig.encrypt_java, "hallServlet");
                logger.debug("玩家[{}]离开房间", playerId);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
            params.clear();
        });
    }

    public static void main(String[] args) {
        DataService ds = new DataServiceImpl();
        Player player = ds.getPlayeInfo(10000092);
        System.out.println(JsonUtils.object2String(player));
    }

    /**
     * 获得玩家基础信息与辅助信息
     **/
    @SuppressWarnings("unchecked")
    public Player getPlayeInfo(long playerId) {
        Map<String, Object> params = new HashMap<>();
        params.put("action", "playerInfo");////基本信息
        params.put("playerID", playerId);
        ReturnMsg rmsg = null;
        try {
            rmsg = HttpUtil.sendData(params, HttpConfig.send_post, HttpConfig.no_encrypt_java, "hallServlet");
        } catch (Exception e) {
            logger.error("获取玩家[{}]基本信息发生未知错误！", playerId, e);
            throw new ManagedException(Window.PLAYER_INFO_FAIL);
        }
        List<Map<String, Object>> datas = rmsg.getResult();
        if (datas == null || datas.isEmpty()) {
            logger.error("获取玩家[{}]基本信息失败！", playerId);
            return null;
        }
        Map<String, Object> data = datas.get(0);
        Map<String, Object> base = (Map<String, Object>) data.get("baseInfo");
        String nickName = MapUtils.getString(base, "nickName");
        String headUrl = MapUtils.getString(base, "headUrl");
        int playerSex = MapUtils.getIntValue(base, "playerSex");
        String presentation = MapUtils.getString(base, "presentation");
        Map<String, Object> assistJSON = MapUtils.getMap(data, "assistInfo");
        int vipLevel = MapUtils.getIntValue(assistJSON, "vipLevel");
        return Player.valueOf(playerId, nickName, headUrl, playerSex, presentation, vipLevel);//基本信息
    }

    /**
     * 更新玩家背包
     * @param player
     */
    public void getBagInfo(Player player) {
        long playerId = player.getPlayerId();
        //获取玩家背包信息
        Map<String, Object> params = new HashMap<>();
        params.put("action", "bagInfo");
        params.put("playerID", playerId);
        ReturnMsg rmsg = new ReturnMsg();
        try {
            rmsg = HttpUtil.sendData(params, HttpConfig.send_post, HttpConfig.no_encrypt_java, "hallServlet");
        } catch (Exception e) {
            logger.error("获取玩家[{}]背包发生未知错误！", playerId, e);
            throw new ManagedException(Window.PLAYER_INFO_FAIL);
        }
        Map<String, Object> data = rmsg.getResult().get(0);
        Map<PropType, Long> bag = new HashMap<>();
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            PropType type = PropType.valueOf(Integer.valueOf(entry.getKey()));
            //TODO 测试数据
            if (playerId >= 10000003 && playerId <= (10000102)) {
                bag.put(type, 0l);
            } else {
                bag.put(type, Long.parseLong(entry.getValue().toString()));
            }
        }
        player.setBagInfo(bag);
    }

    /**
     * 检查token是否正确
     **/
    public boolean checkToken(long playerId, String token, String P, int platformId) {
        Map<String, Object> params = new HashMap<>();
        params.put("token", token);
        params.put("P", P);
        params.put("playerID", playerId);
        params.put("platformId", platformId);
        params.put("action", "analyseToken");
        ReturnMsg rmsg = new ReturnMsg();
        try {
            rmsg = HttpUtil.sendData(params, HttpConfig.send_post, HttpConfig.encrypt_java, "loginServlet");
        } catch (Exception e) {
            logger.error("token验证失败：{}", e.getMessage(), new Object[]{e});
        }
        params.clear();
        return rmsg.getState() == 1;
    }
}
